# @Version        : 1.0
# @Update Time    : 2024/11/17 20:49
# @File           : monitor_service.py
# @IDE            : PyCharm
# @Desc           : 文件描述信息
from typing import List
import os
import platform
import socket
import time
import psutil
from asyncio import gather
from functools import partial
from src.config import settings
from src.log import logger
from src.schemas.monitor_schema import (
    CpuInfo,
    MemoryInfo,
    SysInfo,
    PyInfo,
    SysFiles,
    ServerMonitorModel,
)
from src.utils.toolsutils import ToolsUtils


class MonitorService:
    """系统资源监控服务类,用于监控系统资源和Python环境"""

    @staticmethod
    async def get_cpu_info() -> CpuInfo:
        """
        获取CPU信息,包括核心数和使用率统计

        Returns:
            CpuInfo: 包含CPU信息的对象
        """
        try:
            cpu_num = psutil.cpu_count(logical=True)
            cpu_usage_percent = psutil.cpu_times_percent()
            return CpuInfo(
                cpu_num=cpu_num,
                used=cpu_usage_percent.user,
                sys=cpu_usage_percent.system,
                free=cpu_usage_percent.idle,
            )
        except Exception as e:
            logger.warning("获取CPU信息失败: {}".format(e))
            # 记录错误并返回默认值
            return CpuInfo(cpu_num=0, used=0, sys=0, free=0)

    @staticmethod
    async def get_memory_info() -> MemoryInfo:
        """
        获取系统内存信息

        Returns:
            MemoryInfo: 包含内存使用统计信息的对象
        """
        try:
            mem = psutil.virtual_memory()
            return MemoryInfo(
                total=ToolsUtils.bytes2human(mem.total),
                used=ToolsUtils.bytes2human(mem.used),
                free=ToolsUtils.bytes2human(mem.free),
                usage=mem.percent,
            )
        except Exception as e:
            logger.warning("获取内存信息失败: {}".format(e))
            return MemoryInfo(total="0B", used="0B", free="0B", usage=0)

    @staticmethod
    async def get_system_info() -> SysInfo:
        """
        获取系统信息,包括主机名、IP和操作系统详情

        Returns:
            SysInfo: 包含系统信息的对象
        """
        try:
            hostname = socket.gethostname()
            return SysInfo(
                computer_ip=socket.gethostbyname(hostname),
                computer_name=platform.node(),
                os_arch=platform.machine(),
                os_name=platform.platform(),
                user_dir=settings.system.BASE_PATH,
            )
        except Exception as e:
            logger.warning("获取系统信息失败: {}".format(e))
            return SysInfo(
                computer_ip="未知",
                computer_name="未知",
                os_arch="未知",
                os_name="未知",
                user_dir=settings.system.BASE_PATH,
            )

    @staticmethod
    async def get_python_info() -> PyInfo:
        """
        获取Python环境信息,包括版本和内存使用情况

        Returns:
            PyInfo: 包含Python环境详细信息的对象
        """
        try:
            current_pid = os.getpid()
            current_process = psutil.Process(current_pid)
            start_time_stamp = current_process.create_time()
            current_time_stamp = time.time()
            difference = current_time_stamp - start_time_stamp

            # 计算运行时间
            days = int(difference // (24 * 60 * 60))
            hours = int((difference % (24 * 60 * 60)) // (60 * 60))
            minutes = int((difference % (60 * 60)) // 60)

            # 获取内存信息
            memory_info = psutil.virtual_memory()
            process_memory = current_process.memory_info()

            return PyInfo(
                name=current_process.name(),
                version=platform.python_version(),
                start_time=time.strftime(
                    "%Y-%m-%d %H:%M:%S", time.localtime(start_time_stamp)
                ),
                run_time=f"{days}天{hours}小时{minutes}分钟",
                home=current_process.exe(),
                total=ToolsUtils.bytes2human(memory_info.available),
                used=ToolsUtils.bytes2human(process_memory.rss),
                free=ToolsUtils.bytes2human(memory_info.available - process_memory.rss),
                usage=round((process_memory.rss / memory_info.available) * 100, 2),
            )
        except Exception as e:
            logger.warning("获取Python环境信息失败: {}".format(e))
            return PyInfo(
                name="未知",
                version="未知",
                start_time="未知",
                run_time="未知",
                home="未知",
                total="0B",
                used="0B",
                free="0B",
                usage=0,
            )

    @staticmethod
    async def get_disk_info() -> List[SysFiles]:
        """
        获取所有挂载分区的磁盘使用信息

        Returns:
            List[SysFiles]: 磁盘信息对象列表
        """
        try:
            sys_files = []
            for partition in psutil.disk_partitions():
                try:
                    usage = psutil.disk_usage(partition.mountpoint)
                    sys_files.append(
                        SysFiles(
                            dir_name=partition.device,
                            sys_type_name=partition.fstype,
                            type_name="本地固定磁盘（"
                            + partition.mountpoint.replace("\\", "")
                            + "）",
                            total=ToolsUtils.bytes2human(usage.total),
                            used=ToolsUtils.bytes2human(usage.used),
                            free=ToolsUtils.bytes2human(usage.free),
                            usage=str(usage.percent),
                        )
                    )
                except Exception as e:
                    logger.warning("获取磁盘信息失败: {}".format(e))
                    continue
            return sys_files
        except Exception as e:
            logger.warning("获取所有挂载分区的磁盘使用信息失败: {}".format(e))
            return []

    async def get_monitor_info(self) -> ServerMonitorModel:
        """
        获取完整的系统监控信息

        Returns:
            ServerMonitorModel: 包含所有监控信息的对象
        """
        try:
            # 并发获取所有监控信息
            cpu_info, mem_info, sys_info, py_info, disk_info = await gather(
                self.get_cpu_info(),
                self.get_memory_info(),
                self.get_system_info(),
                self.get_python_info(),
                self.get_disk_info(),
            )

            return ServerMonitorModel(
                cpu=cpu_info,
                mem=mem_info,
                sys=sys_info,
                py=py_info,
                sys_files=disk_info,
            )
        except Exception as e:
            logger.warning("获取完整的系统监控信息失败: {}".format(e))
            # 发生错误时返回默认值
            return ServerMonitorModel(
                cpu=CpuInfo(cpu_num=0, used=0, sys=0, free=0),
                mem=MemoryInfo(total="0B", used="0B", free="0B", usage=0),
                sys=SysInfo(
                    computer_ip="未知",
                    computer_name="未知",
                    os_arch="未知",
                    os_name="未知",
                    user_dir=settings.system.BASE_PATH,
                ),
                py=PyInfo(
                    name="未知",
                    version="未知",
                    start_time="未知",
                    run_time="未知",
                    home="未知",
                    total="0B",
                    used="0B",
                    free="0B",
                    usage=0,
                ),
                sys_files=[],
            )
